14 3-dimensional

I love 3D and wish I had more time to work on the webmorph 3D functions (I made the following gif using it).

But those are made with three.js and I was excited to play with rgl a bit.

library(rgl)
source("R/readOBJ.R")

14.1 Load OBJ

Load the 3D data from an OBJ file using rgl::readOBJ(). If you get the error "Error in order(vlinks[[i]][, 2]) : argument 1 is not a vector", this means a vertex was empty, which the function doesn't seem to be able to handle. I hacked the readOBJ() function a bit and fixed it, so check my github for this if you have the same problem.

obj <- "data/lisa_neutral.obj"
skin <- "data/lisa_neutral.png"

objexample <- readOBJ(
  obj,
  material = list(color = "white",
                  texture = skin))

Just to give you nightmares, this is what the skin looks like for a 3D face in 2D:

14.2 Render scene

Now clear a scene. You might need to install XQuartz if you're on a mac. If you're running this interactively, a small XQuartz window should pop up.

clear3d(type = c("shapes", "lights"))

Add the face as a wireframe object.

wire3d(objexample)

You can include this in a webpage with rglwidget().

rglwidget(width = 600, height = 800) 

14.3 Give Up

I tried to get it to display with the skin, but failed. Then after I rendered the book, I noticed the skin was showing in the book, just not in XQuartz while I was testing. But I was really tired at that point so I gave up and tried something else for today's theme.

These objects are pretty big, so remove it when you're done.

rm(objexample)

14.4 Try Plotly Instead

I know I can do this fast, so I'll make some 3-dimensional data from a multivariate normal distribution using faux, and 3D plot it using plotly.

14.4.1 Simulate multivariate distribution

In faux, you can set the correlations using a matrix, or just the upper right triangle values as a vector. So c(.1, .2, .3) would mean that \(r_{xy} = .1\), \(r_{xz} = .2\), and \(r_{yz} = .3\).

dat_ppp <- faux::rnorm_multi(
  r = c(.9, .9, .9),
  varnames = c("x", "y", "z")
) %>%
  mutate(cors = "+++")

dat_nnp <- faux::rnorm_multi(
  r = c(-.9, -.9, .9),
  varnames = c("x", "y", "z")
) %>%
  mutate(cors = "--+")

dat_pnn <- faux::rnorm_multi(
  r = c(.9, -.9, -.9),
  varnames = c("x", "y", "z")
) %>%
  mutate(cors = "+--")

dat <- bind_rows(dat_ppp, dat_nnp, dat_pnn)

14.4.2 Marker style

Next, set up the marker style.

#set up the marker style
marker_style = list(
    line = list(
      color = "#444", 
      width = 1
    ), 
    opacity = 0.5,
    size = 3
  )

14.4.3 3D Plot

Finally, make the plot and add markers. These plots look cool, but I find them pretty hard for inference with data.

# plot and add markers
plot_ly(data = dat,
        x = ~x, y = ~y, z = ~z, 
        color = ~cors,
        marker = marker_style) %>%
  add_markers()